/*
 *  \file RefExp.h
 *  gre
 *
 *  Created by Kutlak Roman on 26/07/2011.
 *  Copyright 2011 Roman Kutlak. All rights reserved.
 *
 */

#ifndef RefExp_h 
#define RefExp_h

#include <iosfwd>
#include <list>
#ifdef DEBUG
#include <mutex>
#endif
#include "Property.h"
#include "Entity.h"

namespace kutlak {
namespace roman {
namespace gre {
    
    
    /*!
     * \brief Class that represents a referring expression. 
     * 
     * The class is basically a wrapper for a container such as set or a list.
     * Using a class instead of a generic container allows the use of == operator.
     */
    class RefExp { 
    public: 
        
        typedef std::list<Property> ContainerT;
        
        typedef ContainerT::iterator iterator;
        typedef ContainerT::const_iterator const_iterator;
        typedef ContainerT::value_type value_type;
        
        const_iterator begin() const 
        { return mProperties.begin(); }
        
        iterator begin() 
        { return mProperties.begin(); }
        
        const_iterator end() const 
        { return mProperties.end(); }
        
        iterator end() 
        { return mProperties.end(); }
        
#pragma mark -
#pragma mark lifecycle
        
        RefExp(const EntityPtrT& refPtr = EntityPtrT());
        
        RefExp(const RefExp& from);
        
        RefExp(RefExp&& from);
        
        ~RefExp(void);
        
        RefExp& operator=(RefExp from);
        
        friend void swap(RefExp& lhs, RefExp& rhs);
        
#pragma mark -
#pragma mark operators
        
        //! Equality test operator.
        bool operator==(const RefExp& rhs) const;
        
        //! Unequality test operator.
        bool operator!=(const RefExp& rhs) const;
        
#pragma mark -
#pragma mark I/O
        /*
         //! Input parser. 
         friend std::istream& operator>>(std::istream& input, RefExp& obj);
         
         //! Output formatter.
         friend std::ostream& operator<<(std::ostream& out, const RefExp& obj);
         */                
#pragma mark -
#pragma mark operations
        /*! \brief Method adds a property to the content of the RE
         *  Method checks if the property is not in the current RE and if not,
         *  it adds the property to the end of the list of properties in this RE.
         *  \param p property we want to add
         *  \return true if property was added, false if the RE already contains the property 
         */
        bool Add(const Property& p);
        
        bool Add(const RefExp& properties);
        
        /*! \brief Method adds a property to the content of the RE
         *  Method checks if the property is not in the current RE and if not,
         *  it adds the property to the front of the list of properties in this RE.
         *  \param p property we want to add
         *  \return true if property was added, false if the RE already contains the property 
         */
        bool Prepend(const Property& p);
        
        void Clear();
        
        void Sort();
        
        std::string ToString() const;
#pragma mark -
#pragma mark access
        std::list<Property> Properties() const 
        {
            return mProperties;
        }
        
        void SetReferent(const EntityPtrT& refPtr) 
        {
            mReferent = refPtr;
        }
        
        EntityPtrT Referent() const 
        {
            return mReferent;
        }
#pragma mark -
#pragma mark inquiry
        
        bool HasDeterminer() const;
        
        bool Empty() const 
        {
            return mProperties.empty();
        }
        
        size_t Size() const
        {
            return mProperties.size();
        }
        
        inline size_t Length() const 
        {
            return Size();
        }
        
    private:
        ContainerT mProperties;
        EntityPtrT mReferent;
#ifdef DEBUG
        static std::once_flag sOntologyFlag;
#endif
    };
}
}
}
#endif // RefExp_h
